#pragma once
class ref_count {
private:
	size_t count{ 1 };
public:
	void inc_count() { ++count; }
	void dec_count() { --count; }
	int use_count() { return count; }
};

template<class T>
class shared_ptr {
private:
	T* ptr{ nullptr };
	ref_count* count{ nullptr };

	void decrease_count() {
		count->dec_count();
		if (count->use_count() == 0) {
			delete ptr;
			delete count;
		}
	}

public:
	shared_ptr() = default;
	explicit shared_ptr(T* x) :ptr(x), count(new ref_count) {}

	shared_ptr(const shared_ptr& temp) :ptr(temp.ptr) {
		temp.count->inc_count();
		count = temp.count;
	}

	shared_ptr(shared_ptr&& temp) :ptr(temp.ptr), count(temp.count) {}

	shared_ptr& operator=(const shared_ptr& temp) {
		decrease_count();
		count = temp.count;
		count->inc_count();
		ptr = temp.ptr;
		return *this;
	}

	shared_ptr& operator=(shared_ptr&& temp) {
		decrease_count();
		count = temp.count;
		ptr = temp.ptr;
		return *this;
	}

	int use_count() { return count->use_count(); }

	~shared_ptr() { decrease_count(); }

	void reset(T* x) {
		decrease_count();
		ptr = x;
		count = new ref_count();
	}

	T* get() { return ptr; }

	T& operator*() { return *ptr; }

	T* operator->() { return &(operator*()); }

	bool unique() { return count->use_count() == 1; }

	operator bool() { return static_cast<bool>(ptr); }
};

template<class T, class... ARG>
shared_ptr<T> make_shared(ARG&&...arguments) {
	return shared_ptr<T>{new T(forward<ARG>(arguments)...)};
}